﻿#include "stdafx.h"
#ifdef LK_SOUND_WAVE_
namespace LK
{
	namespace Sound
	{
		//Wave类
		Wave::Wave(){
			Channels=0;
			Bits=0;
			Hz=0;
			Volume=1.0;
			isFloat=false;
			lastValue=NULL;
			lastTime=0;
			SetFormat(DefaultHz,DefaultBits,DefaultChannels);//默认音频格式
		}
		Wave::~Wave()
		{
			if(Channels)
				delete []lastValue;
		}
		void Wave::SetFormat(double hz,short bits,short channels,bool isfloat)
		{
			if(channels == Channels && hz==Hz && bits == Bits && isfloat== isFloat)return;
			if(Hz!=hz)
			{
				Hz = hz;
				lastTime = 0;
			}
			Bits = bits;
			isFloat = isfloat;
			if(Channels!=channels)
			{
				if(Channels)delete []lastValue;
				if(channels)
				{
					lastValue = new double[channels];
				}
				else lastValue = NULL;
				for(Channels=0;Channels<channels;++Channels)lastValue[Channels]=0;
			}
		}
		void Wave::SetFormat(const WaveFormat& wfx)
		{
			SetFormat(wfx.Hz,wfx.Bits,wfx.Channels,wfx.IsFloat);
		}
		void Wave::SetFormat()
		{
			SetFormat(DefaultHz,DefaultBits,DefaultChannels);//默认
		}
		PByteArray Wave::HzConvert(const void* sourceData,index_t length,double toHz,short toBits,bool toFloat)
		{
			index_t sourceSampleCount = length/(Bits/8);
			if(toHz<=0)return PByteArray((index_t)0);
			double tmp = (double)toHz/Hz*(toBits/8);
			if((double)buffer.Length<tmp*(Channels+sourceSampleCount))//按照初步预算调整缓存大小
				buffer.Resize((index_t)(tmp*(Channels+sourceSampleCount)));
			unsigned char* pdat = buffer;//目标内存区
			double prop(Volume);//幅值比例关系
			if(!this->isFloat)//源数据非浮点
				prop/=(1ull<<(Bits-1));
			if(!toFloat)//目标非浮点
				prop*=(1ull<<(toBits-1));
			if(Hz>toHz)//往低频转换
			{
				double value;//瞬时幅值
				index_t t_low(0);//低频侧帧编号
				for(index_t t(0);t<sourceSampleCount;t+=Channels)
				{
					lastTime += toHz;//高频时间轴
					for(index_t c(0);c<Channels;++c)//声道切换
					{
						value = prop*GetValue(sourceData,Bits,c+t,this->isFloat);//获取当前幅值
						if(lastTime>=Hz)
						{
							SetValue(pdat,(lastValue[c]+(Hz-(lastTime-toHz))*value)/Hz,toBits,t_low+c,toFloat);//等值幅度
							lastValue[c] = (lastTime-Hz)*value;//剩余面积
						}
						else lastValue[c]+=value*toHz;//面积增加
					}
					if(lastTime>=Hz)
					{
						t_low+=Channels;//前进
						lastTime-=Hz;//剩余时间
					}
				}
				return new Collection::ReferenceArray<u8>(t_low*toBits / 8, pdat);
			}
			else if(Hz<toHz)//往高频转换
			{
				double value;//瞬时幅值
				index_t t_high(0);//高频侧帧编号
				for(index_t t(0);t<sourceSampleCount;t+=Channels)
				{
					lastTime += toHz;//低频时间轴
					tmp = 0;
					for(;;)
					{
						for(index_t c(0);c<Channels;++c)//声道切换
						{
							value = prop*GetValue(sourceData,Bits,c+t,this->isFloat);//获取当前幅值
							if(lastTime>=Hz)
							{
								SetValue(pdat,(lastValue[c]+(Hz-(lastTime-toHz+tmp))*value)/Hz,toBits,t_high+c,toFloat);//等值幅度
								lastValue[c] = 0;//剩余面积
							}
							else lastValue[c]+=value*lastTime;//最终剩余面积
						}
						if(lastTime>=Hz)
						{
							t_high+=Channels;//前进
							lastTime-=Hz;//剩余时间
							tmp = toHz - lastTime;
						}
						else break;
					}
				}
				return new Collection::ReferenceArray<u8>(t_high*toBits / 8, pdat);
			}
			else//频率无变动
			{

				for(index_t i=0;i<sourceSampleCount;++i)
				{
					SetValue(pdat,prop*GetValue(sourceData,Bits,i,this->isFloat),toBits,i,toFloat);
				}
			}
			return new Collection::ReferenceArray<u8>(sourceSampleCount*toBits / 8, pdat);
		}
		PByteArray Wave::ChConvert(const void* sourceData,index_t length,double ,short _Bits,bool _isFloat,short toChannels)
		{
			index_t sourceSampleCount = length/(_Bits/8);//源帧数
			if(toChannels==Channels)//无转换
			{
				return new Collection::ReferenceArray<u8>(sourceSampleCount*_Bits / 8, (unsigned char*)sourceData);
			}
			if(toChannels>Channels)//声道数少的向声道数高的转换
			{
				size_t desCount(sourceSampleCount*toChannels/Channels);//目标单声道帧数
				if((size_t)buffer2.Length<desCount*_Bits/8)buffer2.Resize(desCount*_Bits/8);
				if(toChannels>Channels)desCount -= desCount%toChannels;//修剪
				for(size_t i(0),j(0);i<desCount;i+=toChannels,j+=Channels)
				{
					for(index_t k(0);k<toChannels;++k)
					{
						SetValue((unsigned char*)buffer2,GetValue(sourceData,_Bits,j+k%Channels,_isFloat),_Bits,i+k,_isFloat);
					}
				}
				return new Collection::ReferenceArray<u8>(desCount*_Bits / 8, buffer2);
			}
			else//声道数高的混音到声道数低的
			{
				size_t desCount(sourceSampleCount*toChannels/Channels);//目标单声道帧数
				if((size_t)buffer2.Length<desCount*_Bits/8)buffer2.Resize(desCount*_Bits/8);
				sourceSampleCount -= sourceSampleCount%Channels;//修剪
				double vol = (double)toChannels/Channels;
				desCount = 0;
				for(index_t i(0);i<sourceSampleCount;i+=Channels)//顺着写入
				{
					for(index_t j(0);j<toChannels;++j)//先写入可写入的值
						SetValue(buffer2,GetValue(sourceData,_Bits,j+i,_isFloat)*vol,_Bits,desCount+j,_isFloat);
					for(index_t j(toChannels);j<Channels;++j)//叠加
						SetValue(buffer2,GetValue(sourceData,_Bits,i+j,_isFloat)*vol+GetValue(buffer2,_Bits,desCount+j%toChannels,_isFloat),_Bits,desCount+j%toChannels,_isFloat);
					desCount+=toChannels;
				}
				return new Collection::ReferenceArray<u8>(desCount*_Bits / 8, buffer2);
			}
		}
		double Wave::GetValue(const void *buffer,short bits,size_t sampleIndex,bool isfloat)
		{
			return GetValue((char*)buffer+sampleIndex*bits/8,bits,isfloat);
		}
		void Wave::SetValue(void *buffer,double value,short bits,size_t sampleIndex,bool isfloat)
		{
			SetValue((char*)buffer+sampleIndex*bits/8,value,bits,isfloat);
		}
		double Wave::GetValue(const void *buffer,short bits,bool isfloat)
		{
		    union{
			double value;
			long long llv;
			float fv;
			long lv;
			short sv;
			signed char cv;
		    };
			switch(bits)
			{
			case 64:llv = *((const long long*)buffer);break;
			case 32:lv = *((const long*)buffer);break;
			case 16:sv = *((const short*)buffer);break;
			default:cv = *((const signed char*)buffer);break;
			}
			if(isfloat)
			{
				if(64 == bits)return value;
				if(32 == bits)return fv;
				if(8 == bits)return cv;
			}
			if(64 == bits)return (double)llv;
			if (32 == bits)return (double)lv;
			if (16 == bits)return (double)sv;
			return cv - 128;
		}
		void Wave::SetValue(void *buffer,double value,short bits,bool isfloat)
		{
			if(isfloat)
			{
				if(64 == bits)
				{
					*(double*)buffer = value;
					return;
				}
				else if(32 == bits)
				{
					if(value>1)value=1;
					if(value<-1)value=-1;
					*((float*)buffer) = (float)value;
					return;
				}
				else if(8 == bits)
				{
					if(value>127)value=127;
					if(value<-128)value=-128;
					*((signed char*)buffer) = (char)value;
					return;
				}
			}
			else
			{
				if(64 == bits)
				{
					if(value>(long long)(-1^0x8000000000000000))value=(double)(long long)(-1^0x8000000000000000);
					if(value<(long long)(0x8000000000000000))value=(double)(long long)0x8000000000000000;
					*((long long*)buffer) = (long long)value;
					return;
				}
				else if(32 == bits)
				{
					if(value>2147483647)
						value=2147483647;
					if(value<-2147483648.0)
						value=-2147483648.0;
					*((long*)buffer) =(long)value;
					return;
				}
				else if(16 == bits)
				{
					if(value>=32767.0)value=32767;
					if(value<=-32768.0)value=-32768;
					*((short*)buffer) = (short)value;
					return;
				}
				else
				{
					if(value>127)value=127;
					if(value<-128)value=-128;
					*((unsigned char*)buffer) = (unsigned char)(value + 128);
				}
			}
		}
		WaveFormat Wave::MakeFormat(double hz,short bits,short ch,bool isfloat)
		{
			return WaveFormat(hz, bits, ch, isfloat);
		}
		PByteArray Wave::GetNoise(size_t size,double block)//获取size字节的噪音
		{
			size -= size%(Bits/8);
			if (!size)return PByteArray();
			if(buffer.Length<(index_t)size)buffer.Resize(size);
			if(isFloat && Bits==32)//浮点
			{
				for(size_t i=0;i<size;i+=4)
				{
					double t = Random::GetDefaultRef()->NextDouble();//获取一个浮点值
					if(Random::GetDefaultRef()->Rand()&1)t = -t;
					if(block>1e-10)//网格化
					{
						long long tmp = 0;
						if(t>=block || t<=-block)
							tmp = (long long)(t/block);//取整
						t = ((double)tmp)*block;
					}
					SetValue(buffer+i,Volume*t,Bits,true);//写入值
				}
				return new Collection::ReferenceArray<u8>(size,buffer);
			}
			index_t ub = (index_t)(block * (1ull<<(Bits-1)));
			for(size_t i=0;i<size;i+=Bits/8)
			{
				index_t t = Random::GetDefaultRef()->NextUInt();//获取一个随机值
				t>>= 32-Bits;
				if(ub>0)
				{
					index_t tmp = 0;
					if(t>=ub || t<=-ub)
						tmp = t/ub;//取整
					t = tmp*ub;
				}
				SetValue(buffer+i,Volume*t,Bits,false);//写入值
			}
			return new Collection::ReferenceArray<u8>(size,buffer);
		}
		PByteArray Wave::GetWaveWithSingleHz(double hz,size_t size,double block)
		{
			if(buffer.Length<(index_t)size)buffer.Resize(size);
			size_t count = size*8/Bits;
			unsigned long long mov = 1ull<<(Bits-1);
			for(size_t i=0;i+Channels<=count;i+=Channels)
			{
				for(index_t j=0;j<Channels;++j)
				{
					if(lastValue[j]>1000 || lastValue[j]<-1000)
						lastValue[j] = 0;//复位，lastvalue数组记录时间的相对位移
					double t = std::sin(lastValue[j]);
					if(block>1e-10)//网格化
					{
						long long tmp = 0;
						if(t>=block || t<=-block)
							tmp = (long long)(t/block);//取整
						t = ((double)tmp)*block;
					}
					if(isFloat && Bits==32)SetValue(buffer,t*Volume,32,i+j,true);
					else SetValue(buffer,t*Volume*mov,Bits,i+j,false);
					if(lastValue[j]>2*3.141592653)
						lastValue[j]-=2*3.141592653;
					lastValue[j] += 2*3.141592653/Hz*hz;
				}
			}
			return new Collection::ReferenceArray<u8>(size, (unsigned char*)buffer);
		}
		PWaveData Wave::GetNoiseData(const ptr<Time>& t,double block)//获取time时长的噪音(一个引用)
		{
			if(t<=0)Throw<PSoundException >(L"时间为负");
			PWaveData tdata(new WaveData);
			tdata.SetHz(Hz); tdata.SetBits(Bits); tdata.SetChannels(Channels); tdata.SetIsFloat(isFloat);
			time +=t;
			index_t samples = (index_t)(time*Hz/Time::EverySecond - lastTime);
			lastTime+= samples;
			if(time>Time::EverySecond && lastTime>Hz)
			{
				time%=Time::EverySecond;
				lastTime = (double)((index_t)lastTime%(index_t)Hz);
			}
			if(!samples)return tdata;
			samples *= Bits/8;
			if(buffer.Length<samples)buffer.Resize(samples);
			if(isFloat && Bits==32)//浮点
			{
				for(index_t i=0;i<samples;i+=4)
				{
					double _t = Random::GetDefaultRef()->NextDouble();//获取一个浮点值
					if(Random::GetDefaultRef()->Rand()&1)_t = -_t;
					if(block>1e-10)//网格化
					{
						long long tmp = 0;
						if(_t>=block || _t<=-block)
							tmp = (long long)(_t/block);//取整
						_t = (double(tmp))*block;
					}
					SetValue(buffer+i,Volume*_t,Bits,true);//写入值
				}
				tdata.GetData()=new Collection::ReferenceArray<u8>(samples, buffer);
				return tdata;
			}
			index_t ub = index_t(block * (1ull<<(Bits-1)));
			for(index_t i=0;i<samples;i+=Bits/8)
			{
				index_t _t = Random::GetDefaultRef()->NextUInt();//获取一个随机值
				_t>>= 32-Bits;
				if(ub>0)
				{
					index_t tmp = 0;
					if(_t>=ub || _t<=-ub)
						tmp = _t/ub;//取整
					_t = tmp*ub;
				}
				SetValue(buffer+i,Volume*_t,Bits,false);//写入值
			}
			tdata.GetData()= new Collection::ReferenceArray<u8>(samples, buffer);
			return tdata;
		}
		PWaveData Wave::GetWaveDataWithSingleHz(double hz,const ptr<Time>& t,double block)
		{
			if(t<=0)Throw <PSoundException >(L"时间为负");
			PWaveData tdata(new WaveData);
			tdata.SetHz(Hz); tdata.SetBits(Bits); tdata.SetChannels(Channels); tdata.SetIsFloat(isFloat);
			time +=t;
			index_t samples = (index_t)(time*Hz/Time::EverySecond - lastTime);
			lastTime+= samples;
			if(time>Time::EverySecond && lastTime>Hz)
			{
				time%=Time::EverySecond;
				lastTime = (double)((index_t)lastTime%(index_t)Hz);
			}
			if(!samples)return tdata;
			samples *= Bits/8;
			if(buffer.Length<samples)buffer.Resize(samples);
			size_t count = samples*8/Bits;
			unsigned long long mov = 1ull<<(Bits-1);
			for(size_t i=0;i+Channels<=count;i+=Channels)
			{
				for(index_t j=0;j<Channels;++j)
				{
					if(lastValue[j]>1000 || lastValue[j]<-1000)
						lastValue[j] = 0;//复位，lastvalue数组记录时间的相对位移
					double _t = std::sin(lastValue[j]);
					if(block>1e-10)//网格化
					{
						long long tmp = 0;
						if(_t>=block || _t<=-block)
							tmp = (long long)(_t/block);//取整
						_t = (double(tmp))*block;
					}
					if(isFloat && Bits==32)SetValue(buffer,_t*Volume,32,i+j,true);
					else SetValue(buffer,_t*Volume*mov,Bits,i+j,false);
					if(lastValue[j]>2*3.141592653)
						lastValue[j]-=2*3.141592653;
					lastValue[j] += 2*3.141592653/Hz*hz;
				}
			}
			tdata.GetData()= new Collection::ReferenceArray<u8>(samples, buffer);
			return tdata;
		}
		void Wave::Wait(size_t size)
		{
			if(!size)return;
			long long tmp = (long long)(size/(Hz*Bits/8*Channels)*Time::EverySecond);//应该等待的时间
			long long span = (long long)(((double)Time::GetLocal()-(double)time)*10000000);//获取时间间隔
			if(span>tmp*10)//时间间隔过长，通常是由于卡机或初次等待导致
			{
				time = Time::Now;
				return;
			}
			while(span<tmp)
			{
				Sleep(10);
				span = (long long)((double)(Time::Now-time)*10000000);
			}
			time+=(tmp/10000000.0);
			return;
		}


		//WaveData类
		WaveFormat WaveData::GetFormat()const{ return Wave::MakeFormat(Hz, Bits, Channels, IsFloat); }
		WaveData::WaveData():Hz(DefaultHz),Bits(DefaultBits),Channels(DefaultChannels),IsFloat(false){}

	}
}
#endif
